#pragma once

#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>

#define DEFAULT 8081

class UdpServer{
  private:
    int port;
    std::string ip;
    int sockfd;
  public:
    UdpServer(std::string _ip, int _port = DEFAULT):port(_port),ip(_ip),sockfd(-1)
    {}

    bool InitUdpServer()
    {
      sockfd = socket(AF_INET, SOCK_DGRAM, 0);
      if(sockfd == -1){
        std::cerr << "socket error" << std::endl;
        return false;
      }

      std::cout << "socket succeed, sockfd->" << sockfd << std::endl;

      struct sockaddr_in local;
      memset(&local, 0, sizeof(local));
      bzero(&local, sizeof(local));
      local.sin_family = AF_INET;
      local.sin_port = htons(port);
      local.sin_addr.s_addr = inet_addr(ip.c_str());
      if(bind(sockfd, (struct sockaddr*)&local, sizeof(local)) == - 1){
        std::cerr << "bind error" << std::endl;
        return false;
      }

      std::cout << "bind succeed" << std::endl;
      return true;
    }
    void Start()
    {
#define SIZE 128
      while(true){
        char buffer[SIZE];
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        ssize_t size = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&peer, &len);
        if(size == -1){
          std::cerr << "recvfrom error" << std::endl; 
        }
        else if(size == 0){
          std::cout << "recvfrom the end of socket" << std::endl;
        }
        else{
          buffer[size] = 0;
          int _port = ntohs(peer.sin_port);
          std::string _ip = inet_ntoa(peer.sin_addr);
          //std::cout << "Client send->" << buffer << std::endl;
          std::cout << _port << " " <<  _ip << " send->" << buffer << std::endl;

          int pipes[2];
          std::string res;
          std::string cmd = buffer;
          if("ls" == cmd || "pwd" == cmd || "whoami" == cmd){
            if(pipe(pipes) == -1 ){
              std::cerr << "pipe error" << std::endl;
            }
            dup2(pipes[1], 1);
            int i = 0;
            i = 0;
            pid_t fd = fork();
            if(fd == 0){
              //child
              close(pipes[0]);
              execlp(buffer, buffer, nullptr);
              exit(1);
            }
            //father
            close(pipes[1]);
            char c;
            while(true){
              if(read(pipes[0], &c, 1) > 0)
                res.push_back(c);
              else break;
            }
            waitpid(fd, nullptr,0);
          }
          std::string echo_msg;
          //处理发送信息
          if(res.empty()){
            echo_msg = "Server get->";
            echo_msg += buffer;
          }
          else{
            echo_msg = res;
          }
          sendto(sockfd, echo_msg.c_str(), echo_msg.size(), 0, (struct sockaddr*)&peer, len);
        }
      }
    }
    ~UdpServer()
    {
      if(sockfd != -1) close(sockfd); 
    }
};
